//
//  TransmissionBroker.hpp
//  Simulation
//
//  Created by Christopher Kemsley on 3/5/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#ifndef Simulation_TransmissionBroker_hpp
#define Simulation_TransmissionBroker_hpp

#include "Types.hpp"
#include "Object.hpp"
#include "Timer.hpp"
#include <set>
#include "System.hpp"
#include "StatisticsServer.hpp"

NamespaceBegin




class	TransmissionBroker ;

class	Transmitter ;
class	TransmitterDelegate ;

class	Receiver ;
class	ReceiverDelegate ;

struct	Message ;

struct	TransmitterProfile ;
struct	ReceiverProfile ;


typedef	char DeviceID ;
















struct	ReceiverProfile
{
	ReceiverProfile ( Location const & location , Channel const & channel = Channel(0) ) ;
	ReceiverProfile ( ReceiverProfile const & copy ) ;
	~ReceiverProfile () ;
	
	Location	location ;
	Channel		channel ;
	
	bool	receives	( TransmitterProfile const & profile ) const ;
	void	operator=	( ReceiverProfile const & copy ) ;
} ;


struct	TransmitterProfile : public ReceiverProfile
{
	TransmitterProfile ( Location const & location , Distance const & txRange , Channel const & channel = Channel(0) ) ;
	TransmitterProfile ( TransmitterProfile const & copy ) ;
	~TransmitterProfile () ;
	
	Distance	txRange ;
	
	void	operator=	( TransmitterProfile const & copy ) ;
} ;


class	Message : public Object
{
public:
	
	// Payload
	DeviceID const		sender ;
	DeviceID const		target ;
	
	Byte const*const	bytes ;		// Data block. See BroadcastData.hpp
	Length const		length ;	// Data length
	
	TransmitterProfile const	transmitter ;
	
	
	static Message*	create	( TransmitterProfile const & profile , DeviceID sender , DeviceID target , Byte const * data , unsigned length ) ;
	
	
private:
	Message ( TransmitterProfile const & profile , DeviceID sender , DeviceID target , Byte const * data , unsigned length ) ;
	~Message () ;
} ;



















class	Transmitter
{
public:
	
	Transmitter	( DeviceID const & identifier , TransmitterDelegate & delegate ) ;
	~Transmitter () ;
	
	bool	isTransmitting () const ;
	void	transmit	( Byte const * data , Length length , DeviceID target , TransmitterProfile const & profile ) ;
	void	cancel		() ; // does NOT call transmissionDidComplete
	
private:
	DeviceID				mIdentifier ;
	TransmitterDelegate&	mDelegate ;
	OP<Message>				mCurrent ;			// transient
	DP<Timer>				mCompletionTimer ;	// transient
	Statistics::Node		mStats ;
	
	void	_callback () ;
} ;

class	TransmitterDelegate
{
protected:
	friend class Transmitter ;
	
	virtual void	transmissionDidComplete () = 0 ;
} ;










class	Receiver
{
public:
	
	Receiver ( DeviceID const & identifier , ReceiverProfile const & profile , ReceiverDelegate & delegate ) ;
	~Receiver () ;
	
	bool	isIdle	() const ;
	void	enable	() ; // enables callbacks
	void	disable	() ; // disables callbacks
	
	void	setProfile ( ReceiverProfile const & profile ) ;
	
protected:
	friend class TransmissionBroker ;
	
	void	beginReceipt	( Message * message ) ;
	void	cancelReceipt	( Message * message ) ;
	void	endReceipt		( Message * message ) ;
	
private:
	ReceiverDelegate&		mDelegate ;
	ReceiverProfile			mProfile ;
	OP<Message>				mMessage ;		// transient
	std::set<OP<Message> >	mAllMessages ;	// transient -- 0=idle ; 1=valid ; 2+=garbled
	Statistics::Node		mStats ;
	enum {
		kCallbackEnabled ,
		kCallbackNever ,
		kCallbackIgnore
	} mCallbackState ;
} ;

class	ReceiverDelegate
{
protected:
	friend class Receiver ;
	
	// i.e. line isn't idle
	virtual void	receiveDidBegin () { } ;
	
	// i.e. line is idle
	virtual void	receiveDidFail () { } ;
	virtual void	receiveDidComplete	( Message * message ) = 0 ;
} ;












class	TransmissionBroker : public SystemController
{
private:
	
	std::set<Receiver*>		receivers ;
	std::set<OP<Message> >	messages ;
	std::set<OP<Message> >	pendingAdditions ;
	std::set<OP<Message> >	pendingRemovals ;
	std::set<OP<Message> >	pendingCancellations ;
	
	TransmissionBroker () ;
	~TransmissionBroker () ;
	
	virtual Interval const	minimumTimeInterval () const ;
	
	virtual void	systemDidAdvance	( Interval const & from , Interval const & to , bool isZeroTime ) ;
	
protected:
	
	friend class Transmitter ;
	friend class Receiver ;
	
	static TransmissionBroker&	shared () ;
	
	void	addReceiver		( Receiver * sender ) ;
	void	removeReceiver	( Receiver * sender ) ;
	
	void	addMessage		( Message * message ) ;
	void	removeMessage	( Message * message ) ;
	void	cancelMessage	( Message * message ) ;
} ;












NamespaceEnd

#endif
